package com.waitingsnow.common.share.bridia.net.oauth
{
	import com.waitingsnow.common.share.bridia.utils.BDStringUtils;
	import com.waitingsnow.core.debug.Logger;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLVariables;

	/**
	 * 请求完成时触发该事件,访问BDOAuthConnection.data获取服务器端返回的数据.
	 */	
	
	[Event(name="complete", type="flash.events.Event")]
	
	/**
	 * 请求错误时抛出该事件.
	 */	
	
	[Event(name="ioError", type="flash.events.IOErrorEvent")]
	
	/**
	 * 每次请求接口时都会抛出该事件.
	 */	
	
	[Event(name="httpStatus", type="flash.events.HTTPStatusEvent")]
	
	/**
	 * 跨域请求发生安全错误时抛出该事件. 
	 */	
	
	[Event(name="securityError", type="flash.events.SecurityErrorEvent")]
	
	/**
	 * 
	 * @author <a href="http://www.bridia.com">Bridia.com</a> : Tensharp
	 * 
	 * <p><b>示例地址： <a href="http://oauth.bridia.com">http://oauth.bridia.com</a></b></p>
	 * <p><b>该版本只支持OAuth 1.0</b></p>
	 * 
	 * <p>OAuth详细说明文档请参考:<a href="http://oauth.net" target="_blank">OAuth.net</a></p>
	 * 
	 * <p>BDOAuthConnection类可以帮助用户生成一个包含oauth签名以及其他参数的URLRequest或直接访问需要OAuth的接口.</p>
	 * <p>OAuth参数传递的方式只提供以下两种方法(我们不推荐URL地址传递参数.) : </p>
	 * 
	 * <ul>
	 * 	<li>使用URLVariables.</li>
	 * 	<li>使用HTTP Header (header当中只包含了OAuth参数,接口要求的参数仍然会放在URLVariables当中,请通过URLRequest.data获取.)</li>
	 * </ul>
	 * 
	 * <p>具体请参考示例.</p>
	 */
	
	public class BDOAuthConnection extends EventDispatcher
	{
        //==========================================================================
        //  Class variables
        //==========================================================================
        
		///
		///	[OAuth Object.]
		///
		
		private var _oauth:BDOAuth;
		
		/**
		 *
		 * <p>获取OAuthConnection使用的OAuth对象.</p>
		 *  
		 * @return 
		 * 
		 */		
		
		public function get oauth ():BDOAuth
		{
			return _oauth;
		}
		
		///
		///	[Base url]
		///
		
		/**
		 * @private 
		 */		
		
		private var _base_url:String = "";
		
		/**
		 * <p>开放API的域名,有服务提供商提供.</p> 
		 * @return 
		 */		

		public function get base_url():String
		{
			return _base_url;
		}

		/// [setter]
		
		public function set base_url(value:String):void
		{
			_base_url = value;
		}

		///
		
		///
		///	[OAuth Token]
		///
		
		/**
		 * @private 
		 */		
		
		private var _oauth_token:String;
		
		/**
		 * <p>OAuth token : Request token和Access Token后获取的oauth token</p>
		 * <p>access token后获取的oauth_token可保存下来永久使用.</p>
		 * 
		 * @return 
		 */
		
		public function get oauth_token ():String
		{
			return _oauth_token;
		}
		
		///[setter]
		
		public function set oauth_token (value:String):void
		{
			_oauth_token = value;
		}
		
		///
		///	[OAuth token secret]
		///
		
		/**
		 * @private 
		 */		
		
		private var _oauth_token_secret:String;
		
		/**
		 * <p>OAuth secret : Request token和Access Token后获取的oauth secret</p>
		 * <p>access token后获取的oauth_token_secret可保存下来永久使用.</p>
		 * 
		 * @return 
		 */		
		
		public function get oauth_token_secret ():String
		{
			return _oauth_token_secret;
		}
		
		/// [setter]
		
		public function set oauth_token_secret (value:String):void
		{
			_oauth_token_secret = value;
		}
		
		///
		/// [Data]
		///
		
		/**
		 * 
		 * <p>访问接口后返回的数据.</p>
		 *  
		 * @return 
		 * 
		 */		
		
		public function get data ():Object
		{
			if (!loader)
			{
				return null;
			}
			
			//
			
			return loader.data;
		}
		
		/// [URLLoader]
		
		/**
		 * @private 
		 */		
		
		private var loader:URLLoader;
		
		/// [URLRequest]
		
		/**
		 * @private 
		 */		
		
		private var request:URLRequest;
		
		///	[Headers Array]
		
		/**
		 * @private 
		 */		
		
		private var headers:Array;
		
		///	[URLVariables]
		
		/**
		 * @private 
		 */		
		
		private var variables:URLVariables;
		
		///	[Parameter]
		
		/**
		 * @private
		 */		
		
		private var parameter:Object = {};
		
		///
		///	[Constructor]
		///
		
		/**
		 * <p>创建一个BDOAuthConnection对象.</p>
		 * 
		 * @param consumerKey 向服务商申请应用通过时由服务商提供 (ConsumerKey,参与签名.).
		 * @param consumerSecret 向服务商申请应用通过时由服务商提供 (ConsumerSecret,参与签名.).
		 * @param nonceLength oauth_nonce的长度(建议长度位16-32位)
		 * 
		 */	
		
		public function BDOAuthConnection (consumerKey:String, consumerSecret:String, nonceLength:int = 32)
		{
			_oauth = new BDOAuth (consumerKey, consumerSecret, nonceLength);
		}
		
		/**
		 * <p>访问一个接口.</p> 
		 * 
		 * @param method HTTP请求方式
		 * @param request_url 请求的URL,需要参与签名.
		 * @param resource web应用(跨域)使用.
		 * @param is_header 是否将OAuth参数装载到Header中.
		 */		
		
		public function connect (method:String, request_url:String, resource_url:String = null, is_header:Boolean = false):void
		{
			loader = new URLLoader (getOAuthRequest (method, request_url, resource_url));
			
			//
			
			loader.addEventListener (Event.COMPLETE, loadCompleteHandler);
			loader.addEventListener (IOErrorEvent.IO_ERROR, loadErrorHandler);
			loader.addEventListener (HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
			loader.addEventListener (SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
		}
		
		/**
		 * <p>获取一个已经包含了OAuth签名和参数的URLRequest对象.</p> 
		 * 
		 * @param method HTTP请求方式
		 * @param request_url 请求的URL,需要参与签名.
		 * @param resource web应用(跨域)使用.
		 * @param is_header 是否将OAuth参数装载到Header中.
		 */	
		
		public function getOAuthRequest (method:String, request_url:String, resource_url:String = null, use_header:Boolean = false):URLRequest
		{
			request = new URLRequest ();
			
			request.url    = request_url;
			request.method = method;
			
			//
			
			variables = new URLVariables ();
			
			//
			
			var headers:Array = [];
			
			//
			
			if (oauth_token && oauth_token.length > 0)
			{
				parameter.oauth_token = oauth_token;
				
				//
				
				oauth.oauth_token        = oauth_token;
				oauth.oauth_token_secret = oauth_token_secret;
			}
			
			//
			
			if (use_header)
			{
				parameter.oauth_signature = BDStringUtils.special_url_encoder (oauth.signature (oauth.baseString (method, request_url, resource_url)));
			}
			else
			{
                var baseStr:String = oauth.baseString (method, request_url, resource_url);
                Logger.debug(baseStr);
				parameter.oauth_signature = oauth.signature (baseStr);
			}
			
			//
			
			parameter.oauth_nonce            = oauth.oauth_nonce;
			parameter.oauth_timestamp        = oauth.oauth_timestamp;
			parameter.oauth_signature_method = oauth.oauth_signature_method;
			parameter.oauth_version          = oauth.version;
			parameter.oauth_consumer_key     = oauth.oauth_consumer_key;
			
			//
			
			for (var i:String in parameter)
			{
				if (use_header)
				{
					if (i.indexOf ("oauth_") > -1)
					{
						headers.push (i + "=" + '"' + parameter[i] + '"');
					}
					else
					{
						variables[i] = parameter[i];
					}
				}
				else
				{
					variables[i] = parameter[i];
				}
			}
			
			//
			
			request.data = variables;
			
			//
			
			if (use_header)
			{
				if (base_url == "" || !base_url)
				{
					throw "";
				}
				
				//
				
				headers.sort ();
				
				//

				request.requestHeaders.push (new URLRequestHeader ("Authorization", 'OAuth realm="' + base_url + '/",' + headers.join (",")));
			}
			
			parameter = {};
			
			//
			
			return request;
		}
		
		/**
		 * <p>添加一个OAuth参数.需要注意的是参数里不能包括oauth_token,oauth_token_secret这两个参数.</p>
		 * 
		 * @param name 参数名.
		 * @param value 参数值
		 * @param encode 是否对参数进行编码.
		 * 
		 */
		
		public function addOAuthParameters (name:String, value:String, encode:Boolean = false):void
		{
			if (!name || !value || name.length == 0 || value.length == 0)
			{
				return;
			}
			
			//
			
			parameter[name] = value;
			oauth.addOAuthParameters (name, value, encode);
		}
		
		///
		///	[Load complete handler]
		///
		
		/**
		 *
		 * @private
		 * 
		 * <p>加载完成事件</p>
		 *  
		 * @param event
		 * 
		 */		
		
		private function loadCompleteHandler (event:Event):void
		{
			dispatchEvent (new Event (event.type, event.bubbles, event.cancelable));
		}
		
		///
		///	[Load error handler]
		///
		
		/**
		 * @private 
		 * 
		 * <p>错误事件</p>
		 *  
		 * @param event
		 * 
		 */		
		
		private function loadErrorHandler (event:IOErrorEvent):void
		{
			dispatchEvent (new IOErrorEvent (event.type, event.bubbles, event.cancelable, event.text));
		}
		
		///
		///	[Http status handler]
		///
		
		/**
		 * @private
		 * 
		 * <p>http status event.</p>
		 * 
		 * @param event
		 * 
		 */		
		
		private function httpStatusHandler (event:HTTPStatusEvent):void
		{
			dispatchEvent (new HTTPStatusEvent (event.type, event.bubbles, event.cancelable, event.status));
		}
		
		///
		///	[Security error handler]
		///
		
		/**
		 * @private
		 * 
		 * <p>Security error handler</p>
		 *  
		 * @param event
		 * 
		 */		
		
		private function securityErrorHandler (event:SecurityErrorEvent):void
		{
			dispatchEvent (new SecurityErrorEvent (event.type, event.bubbles, event.cancelable, event.text));
		}
	}
}